/*
Copyright (C) 2022-2024 Inspur Corp. All Rights Reserved.

SPDX-License-Identifier: Apache-2.0
*/
package service

import (
	"did-service/bean/entity"
	"did-service/bean/model"
	"did-service/bean/param"
	model2 "did-service/chain/model"
	"did-service/common/constant"
	"did-service/common/db"
	"did-service/common/utils"
	"did-service/common/uuid"
	"did-service/config"
	"time"

	errors "github.com/pkg/errors"
)

func (ds DidService) InsertIssuer(param *param.AuthorityIssuerParam) error {

	issuer, err := ds.GetIssuerByWalletId(param.WalletId)
	if issuer != nil {
		return errors.New("该用户已注册发证方！")
	}
	ddk, err := ds.GetDocumentKeyByDid(param.Did)
	if err != nil {
		log.Errorf("get document key by did error: %v", err)
		return err
	}

	if ddk == nil {
		log.Warning("document key not exist")
		return errors.New("document key not exist")
	}

	id := uuid.Generate()
	nowTime := time.Now()
	issuerTable := &entity.AuthorityIssuer{
		Did:              param.Did,
		WalletId:         param.WalletId,
		Name:             param.Name,
		Status:           constant.Status0,
		LongDescription:  param.LongDescription,
		ShortDescription: param.ShortDescription,
		ServiceType:      param.ServiceType,
		CreatedTime:      nowTime,
		UpdatedTime:      nowTime,
	}
	// Check if issuer exists and is deleted
	existingIssuer, err := ds.GetIssuerByDid(issuerTable.Did)
	if err != nil {
		log.Error(err)
		return err
	}
	if existingIssuer != nil && existingIssuer.Status == constant.Status2 {
		// Update existing issuer
		_, err = ds.engine.Where("id = ?", existingIssuer.Id).Update(issuerTable)
		if err != nil {
			log.Error(err)
			return err
		}
		return nil
	}
	if existingIssuer == nil {
		issuerTable.Id = id
		// Insert new issuer
		_, err = ds.engine.InsertOne(issuerTable)
		if err != nil {
			log.Error(err)
			return err
		}
		issuerInfos := model2.IssuerInfo{
			Id:          id,
			Did:         param.Did,
			Name:        param.Name,
			ServiceType: param.ServiceType,
			Endpoint:    config.Get("did.endpoint", constant.DefaultServiceResolveEndpoint),
		}
		go func(id string, issuerInfo *model2.IssuerInfo) {
			txId, _ := ds.getChainClient().SaveIssuerInfo(issuerInfo)
			didDocument := entity.AuthorityIssuer{
				TxId: txId,
			}
			_, err := ds.engine.Where("id = ?", id).Cols("tx_id").Update(&didDocument)
			if err != nil {
				log.Errorf("updata did txid error: %v", err)
			}
		}(issuerTable.Id, &issuerInfos)
	} else {
		return errors.New("注册失败,发证方已存在")
	}
	return nil
}

func (ds DidService) GetIssuerByDid(did string) (*entity.AuthorityIssuer, error) {
	issuer := &entity.AuthorityIssuer{}
	ok, err := ds.engine.Where("did = ?", did).Get(issuer)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	if !ok {
		return nil, nil
	}
	return issuer, nil
}

func (ds DidService) GetDocumentKeyByDid(id string) (*entity.DidDocumentKey, error) {
	DidDocument := &entity.DidDocumentKey{}
	ok, err := ds.engine.Where("key_id = ?", id+constant.DefaultKey1Subfix).Get(DidDocument)
	if err != nil {
		log.Error(err)
		return nil, err
	}

	if !ok {
		return nil, nil
	}

	return DidDocument, nil
}
func (ds DidService) GetWalletByDid(id string) (*entity.DidDocument, error) {
	DidDocument := &entity.DidDocument{}
	_, err := ds.engine.Where("did = ?", id).Get(DidDocument)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	return DidDocument, nil
}

func (ds DidService) GetIssureByDid(id string) (*entity.AuthorityIssuer, error) {
	issuer := &entity.AuthorityIssuer{}
	_, err := ds.engine.Where("did = ?", id).Get(issuer)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	return issuer, nil
}

func (ds DidService) GetPukByDid(id string) (*entity.DidDocumentKey, error) {
	didDocumentKey := &entity.DidDocumentKey{}
	_, err := ds.engine.Where("key_id = ?", id+constant.DefaultKey1Subfix).Get(didDocumentKey)
	if err != nil {
		log.Error(err)
		return nil, err
	}
	return didDocumentKey, nil
}

func (ds DidService) DeleteIssuer(id string) error {

	issuer := entity.AuthorityIssuer{
		Id:     id,
		Status: constant.Status2,
	}
	_, err := ds.engine.Where("id = ?", issuer.Id).Cols("status").Update(issuer)
	if err != nil {
		log.Error(err)
		return err
	}
	return nil
}

func (ds DidService) PutIssuer(id string, name string) error {

	issuer := entity.AuthorityIssuer{
		Id:     id,
		Status: name,
	}
	_, err := ds.engine.Where("id = ?", issuer.Id).Cols("status").Update(issuer)
	if err != nil {
		log.Error(err)
		return err
	}
	return nil
}

func (ds DidService) GetIssuer(id string) (*model.IssuerListResponse, error) {
	issuers := make([]entity.AuthorityIssuer, 0)
	query := ds.engine.Where("id = ? ", id).Desc("updated_time")
	err := query.Find(&issuers)
	if err != nil {
		log.Errorf("query func GetIssuerList error: %s", err)
		return nil, err
	}

	endpoint := config.Get("did.endpoint", "")
	content := make([]model.IssuerList, 0)
	for _, issuer := range issuers {
		documentKey, err := ds.GetPukByDid(issuer.Did)
		if err != nil {
			log.Errorf("get documentKey by issuer id error: %v", err)
			return nil, err
		}
		content = append(content, model.IssuerList{
			ID:               issuer.Id,
			Did:              issuer.Did,
			WalletId:         issuer.WalletId,
			Name:             issuer.Name,
			PubKey:           documentKey.PubKey,
			Endpoint:         endpoint,
			ServiceType:      issuer.ServiceType,
			Status:           issuer.Status,
			ShortDescription: issuer.ShortDescription,
			LongDescription:  issuer.LongDescription,
			CreatedTime:      issuer.CreatedTime.Format(constant.TimeLayout),
		})
	}
	response := model.IssuerListResponse{Content: content}
	return &response, nil
}

func (srv DidService) GetIssuerByWalletId(id string) (*model.IssuerList, error) {
	var issuer entity.AuthorityIssuer
	//	sql := `select A.id, A.did, A.name, A.pub_key, A.status, A.service_type,
	//A.version, A.short_description, A.long_description,A.created_time, A.updated_time
	//from authority_issuer A
	//left join did_document B on A.did=B.did
	//where B.wallet_id = ?`
	ok, err := srv.engine.Where("wallet_id = ? and status in ('0', '1')", id).Get(&issuer)
	if err != nil {
		log.Errorf("get issuer by wallet id error: %v", err)
		return nil, err
	}
	if !ok {
		return nil, nil
	}
	documentKey, err := srv.GetPukByDid(issuer.Did)
	if err != nil {
		log.Errorf("get documentKey by issuer id error: %v", err)
		return nil, err
	}
	endpoint := config.Get("did.endpoint", "")
	result := model.IssuerList{
		ID:               issuer.Id,
		Did:              issuer.Did,
		WalletId:         issuer.WalletId,
		Name:             issuer.Name,
		PubKey:           documentKey.PubKey,
		Endpoint:         endpoint,
		ServiceType:      issuer.ServiceType,
		Status:           issuer.Status,
		ShortDescription: issuer.ShortDescription,
		LongDescription:  issuer.LongDescription,
		CreatedTime:      issuer.CreatedTime.Format(constant.TimeLayout),
	}
	return &result, nil
}

func (ds DidService) GetIssuerListEnum() (*model.IssuerListEnumResp, error) {
	issuers := make([]entity.AuthorityIssuer, 0)
	query := ds.engine.Where("status = '1'").Desc("updated_time")
	err := query.Find(&issuers)
	if err != nil {
		log.Errorf("query func GetIssuerList error: %s", err)
		return nil, err
	}
	content := make([]model.IssuerEnumList, 0)
	for _, issuer := range issuers {
		content = append(content, model.IssuerEnumList{
			Id:   issuer.Id,
			Name: issuer.Name,
		})
	}
	response := model.IssuerListEnumResp{Content: content}
	return &response, nil
}

func (ds DidService) QueryIssuer(pageSize, pageNo int, status, name string) *db.Page {

	page := db.NewPage(0, pageNo).SetPageSize(pageSize)
	var countEntity entity.AuthorityIssuer

	args := make([]interface{}, 0)
	condition := "status != '2'"
	if status != "" {
		condition = utils.StrJoin(condition, " and status = ? ")
		args = append(args, status)
	}
	if name != "" {
		condition = utils.StrJoin(condition, " and name = ? ")
		args = append(args, name)
	}
	count, err := ds.engine.Where(condition, args...).Count(&countEntity)
	if err != nil {
		log.Errorf("query Issuer list count error: %s", err)
		return nil
	}
	page.SetTotal(count)

	issuers := make([]entity.AuthorityIssuer, 0)
	err = ds.engine.Where(condition, args...).Desc("updated_time").Limit(pageSize, (pageNo-1)*pageSize).Find(&issuers)
	if err != nil {
		log.Errorf("query Issuer GetIssuerList error: %s", err)
		return nil
	}
	endpoint := config.Get("did.endpoint", "")
	content := make([]model.IssuerContent, 0)
	for _, issuer := range issuers {
		content = append(content, model.IssuerContent{
			ID:               issuer.Id,
			Did:              issuer.Did,
			Name:             issuer.Name,
			Endpoint:         endpoint,
			ShortDescription: issuer.ShortDescription,
			LongDescription:  issuer.LongDescription,
			ServiceType:      issuer.ServiceType,
			Status:           issuer.Status,
			CreatedTime:      issuer.CreatedTime.Format(constant.TimeLayout),
			UpdatedTime:      issuer.UpdatedTime.Format(constant.TimeLayout),
		})
	}
	page.CreatePage(content)
	return page
}
